#include <os/time.h>
#include <os/mm.h>
#include <os/irq.h>
#include <type.h>

LIST_HEAD(timers);

uint64_t time_elapsed = 0;
uint32_t time_base = 0;

void timer_create(TimerCallback func, void* parameter, uint64_t tick)
{
    disable_preempt();

    // TODO:
    pcb_t *pcb;
    pcb = list_entry(parameter, pcb_t, list);
    pcb->sleep.timeout_tick = get_ticks() + tick;
    pcb->sleep.callback_func = func;
    pcb->sleep.parameter = parameter;
    list_add_tail(&(pcb->sleep.list), &(timers));

    enable_preempt();
}

void timer_check()
{
    disable_preempt();

    /* TODO: check all timers
     *  if timeouts, call callback_func and free the timer.
     */
    list_node_t *sleep_node, *tmp;
    uint64_t current_ticks;
    timer_t* sleep_timer;
    sleep_node = timers.next;
    current_ticks = get_ticks();
    while(sleep_node != &(timers)){
        sleep_timer = list_entry(sleep_node, timer_t, list);
        if(current_ticks >= sleep_timer->timeout_tick){
            sleep_timer->callback_func(sleep_timer->parameter);
            tmp = sleep_node;
            sleep_node = sleep_node->next;
            list_del(tmp);
        }
        else
            sleep_node = sleep_node->next;
    }

    enable_preempt();
}

uint64_t get_ticks()
{
    __asm__ __volatile__(
        "rdtime %0"
        : "=r"(time_elapsed));
    return time_elapsed;
}

uint64_t get_timer()
{
    return get_ticks() / time_base;
}

uint64_t get_time_base()
{
    return time_base;
}

void latency(uint64_t time)
{
    uint64_t begin_time = get_timer();

    while (get_timer() - begin_time < time);
    return;
}
